package com.stillalive.mq.mqserver.core;

import com.stillalive.mq.common.MqException;

/**
 * 实现交换机的转发规则
 * 借助这个类验证bindingKey是否合法
 */
public class Router {
    // 校验规则
    public boolean checkBindingKey(String bindingKey){
        if(bindingKey.length() == 0){
            // direct/fanout交换机，bindingKey是用不上的
            return true;
        }
        for(int i = 0; i < bindingKey.length(); i++) {
            char ch = bindingKey.charAt(i);
            if (ch >= 'A' && ch <= 'Z') {
                continue;
            }
            if (ch >= 'a' && ch <= 'z') {
                continue;
            }
            if (ch >= '0' && ch <= '9') {
                continue;
            }
            if (ch == '_' || ch == '.' || ch == '*' || ch == '#') {
                continue;
            }
            return false;
        }
        // 检查 * 或者 # 是否是独立的部分
        // 这里split参数需要正则表达式，此处需要当作原始文本进行匹配
        String[] words = bindingKey.split("\\.");
        for(String word : words){
            // 检查word长度 > 1且包含了*或者#，就是非法的格式了
            if(word.length() > 1 && (word.contains("*") || word.contains("#"))){
                return false;
            }
        }
        // 约定通配符之间的相邻关系
        // 多个#不能相连，#和*不能相连，但是多个*可以相连
        for(int i = 0; i < words.length-1; i++){
            // 连续两个##
            if(words[i].equals("#") && words[i+1].equals("#")){
                return false;
            }
            // #*
            if(words[i].equals("#") && words[i+1].equals("*")){
                return false;
            }
            // *#
            if(words[i].equals("*") && words[i+1].equals("#")){
                return false;
            }
        }
        return true;
    }
    public boolean checkRoutingKey(String routingKey){
        if(routingKey.length() == 0){
            // 空字符串，合法的
            return true;
        }
        for(int i = 0; i < routingKey.length(); i++){
            char ch =  routingKey.charAt(i);
            if(ch >= 'A' &&  ch <= 'Z'){
                continue;
            }
            if(ch >= 'a' && ch <= 'z'){
                continue;
            }
            if(ch >= '0' && ch <= '9'){
                continue;
            }
            if(ch == '_' || ch == '.'){
                continue;
            }
            // 该字符不是上述任何一种合法情况，直接返回false
            return false;
        }
        // 每个字符都检查过，没有遇到非法情况，直接返回true
        return true;
    }

    // 判定绑定对象是否可以绑定
    public boolean route(ExchangeType exchangeType, Binding binding, Message message) throws MqException {
        if(exchangeType == ExchangeType.FANOUT){
            // 如果是FANOUT类型，则该交换机上所有的队列都需要转发
            return true;
        }else if(exchangeType == ExchangeType.TOPIC){
            return routeTopic(binding, message);
        }else {
            throw new MqException("[Router] 交换机类型非法！exchangeType=" + exchangeType);
        }
    }
    private boolean routeTopic(Binding binding, Message message) throws MqException {
        String[] bindingTokens = binding.getBindingKey().split("\\.");
        String[] routingTokens = message.getRoutingKey().split("\\.");
        // 引入两个下标，指向上述两个数组，初始情况下都为0
        int bindingIndex = 0;
        int routingIndex = 0;
        while(bindingIndex < bindingTokens.length && routingIndex < routingTokens.length){
            if(bindingTokens[bindingIndex].equals("*")) {
                bindingIndex++;
                routingIndex++;
                continue;
            }else if(bindingTokens[bindingIndex].equals("#")) {
                bindingIndex++;
                if(bindingIndex == bindingTokens.length){
                    // #后面没东西了，此时一定能匹配成功
                    return true;
                }
                // #后面还有东西
                routingIndex = findNextMatch(routingTokens, routingIndex, bindingTokens[bindingIndex]);
                if(routingIndex == -1){
                    // 没找到匹配的结果，匹配失败
                    return false;
                }
                // 找到匹配的位置，继续往后匹配
                bindingIndex++;
                routingIndex++;
            } else {
                // 普通字符串
                if(!bindingTokens[bindingIndex].equals(routingTokens[routingIndex])){
                    return false;
                }
                bindingIndex++;
                routingIndex++;
            }
        }
        // 判定是否是双方同时到达末尾
        if(bindingIndex == bindingTokens.length && routingIndex == routingTokens.length){
            return true;
        }
        return false;
    }
    // 找下一个和bindingToken匹配的下标
    private int findNextMatch(String[] routingTokens, int routingIndex, String bindingToken) {
        for (int i = routingIndex; i < routingTokens.length; i++) {
            if(routingTokens[i].equals(bindingToken)){
                return i;
            }
        }
        return -1;
    }
}
